package com.linkgie.galaxyframework.crypto.context;

import com.linkgie.galaxyframework.crypto.Algorithm;
import com.linkgie.galaxyframework.crypto.AlgorithmCodec;
import com.linkgie.galaxyframework.crypto.spi.Cryptobytes;
import com.linkgie.galaxyframework.crypto.spi.CryptobytesCodec;
import com.linkgie.galaxyframework.utils.BinaryUtils;

/**
 * 密码数据编码；
 * 
 * @author Hike
 *
 */
public class Encoding {

//	public static final byte STANDAR_ENCODING_MAGIC = (byte) 00;

	/**
	 * 编码扩展长度，单位：字节；
	 * <p>
	 * 
	 * 即：编码后数据的长度相对原数据增长的长度；
	 */
	private static final int ENCODING_EXT_LENGTH = 2;

	private final AlgorithmCodec ALGORITHM_CODEC;

	private Encoding(AlgorithmCodec algorithmCodec) {
		this.ALGORITHM_CODEC = algorithmCodec;
	}

	public static Encoding createInstance(AlgorithmCodec algorithmCodec) {
		return new Encoding(algorithmCodec);
	}

	public int getExtendLength() {
		return ENCODING_EXT_LENGTH;
	}

	/**
	 * 解码指定的密码数据中标记的算法类型；
	 * <p>
	 * 
	 * 如果编码格式不正确或者算法类型不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	public Algorithm decodeAlgorithm(byte[] cryptoBytes) {
		return decodeAlgorithm(cryptoBytes, 0, cryptoBytes.length);
	}

	/**
	 * 解码指定的密码数据中标记的算法类型；
	 * <p>
	 * 
	 * 如果编码格式不正确或者算法类型不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	public Algorithm decodeAlgorithm(byte[] cryptoBytes, int offset, int length) {
		if (cryptoBytes.length < offset + length) {
			return null;
		}
		if (length < ENCODING_EXT_LENGTH) {
			return null;
		}
//		if (cryptoBytes[offset] != STANDAR_ENCODING_MAGIC) {
//			return null;
//		}
		short code = BinaryUtils.toShort(cryptoBytes, offset);
		return ALGORITHM_CODEC.getAlgorithm(code);
	}

	/**
	 * 解码指定的密码数据中的原数据内容；
	 * <p>
	 * 
	 * 如果编码格式不正确或者标记的算法类型不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	public byte[] decodedContent(byte[] cryptoBytes) {
		Algorithm algorithm = decodeAlgorithm(cryptoBytes);
		if (algorithm == null) {
			return null;
		}
		byte[] content = new byte[cryptoBytes.length - ENCODING_EXT_LENGTH];
		System.arraycopy(cryptoBytes, ENCODING_EXT_LENGTH, content, 0, content.length);
		return content;
	}

	/**
	 * 解码指定的密码数据中的原数据内容；
	 * <p>
	 * 
	 * 如果编码格式不正确或者标记的算法类型不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	public byte[] decodedContent(byte[] cryptoBytes, int offset, int length) {
		Algorithm algorithm = decodeAlgorithm(cryptoBytes, offset, length);
		if (algorithm == null) {
			return null;
		}
		byte[] content = new byte[length - ENCODING_EXT_LENGTH];
		System.arraycopy(cryptoBytes, offset + ENCODING_EXT_LENGTH, content, 0, content.length);
		return content;
	}

	/**
	 * 解码指定的密码数据中的原数据内容；
	 * <p>
	 * 
	 * 如果编码格式不正确或者标记的算法类型不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	public Cryptobytes decodedContent(byte[] cryptoBytes, int offset, int length, CryptobytesCodec<?> codec) {
		Algorithm algorithm = decodeAlgorithm(cryptoBytes, offset, length);
		if (algorithm == null) {
			return null;
		}
		if (!codec.isSupported(cryptoBytes, offset + ENCODING_EXT_LENGTH, length - ENCODING_EXT_LENGTH)) {
			return null;
		}
		Cryptobytes cbytes = codec.decode(cryptoBytes, offset + ENCODING_EXT_LENGTH, length - ENCODING_EXT_LENGTH);
		return cbytes;
	}

	public boolean isSupported(byte[] cryptoBytes, int offset, int length, CryptobytesCodec<?> codec) {
		return codec.isSupported(cryptoBytes, offset + ENCODING_EXT_LENGTH, length - ENCODING_EXT_LENGTH);
	}

	public byte[] encode(Algorithm algorithm, Cryptobytes cryptoBytes) {
		byte[] bytesContent = cryptoBytes.getEncodedBytes();
		return encode(algorithm, bytesContent);
	}
	
	public byte[] encode(Algorithm algorithm, byte[] bytesContent) {
		byte[] encodedBytes = new byte[bytesContent.length + ENCODING_EXT_LENGTH];
//		encodedBytes[0] = STANDAR_ENCODING_MAGIC;
		BinaryUtils.toBytes(algorithm.getCode(), encodedBytes, 0);
		System.arraycopy(bytesContent, 0, encodedBytes, ENCODING_EXT_LENGTH, bytesContent.length);
		return encodedBytes;
	}
}
